﻿using MoneyWentWhere.DataModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MoneyWentWhere.Extensions
{
    public class UsdExchangeRates
    {
        public static UsdExchangeRates Instance;
        public Dictionary<String, List<Rate>> _dict = new Dictionary<String, List<Rate>>();

        public UsdExchangeRates(IList<Account> accounts)
        {
            var transfers = accounts
                .SelectMany(x => x.Transactions)
                .Where(x => x.Kind == TransactionKind.Transfer);

            foreach (var tf in transfers)
            {
                String otherCur = tf.TransferToTx.Account.Currency.Id;
                if (tf.Amount != 0 &&
                    tf.TransferToTx.Amount != 0 &&
                    tf.Account.Currency.Id == "USD" &&
                    otherCur != "USD")
                {
                    decimal rate = -tf.Amount / tf.TransferToTx.Amount;
                    AddRate(tf.Date, otherCur, rate);
                }
            }

            // Add Defaults
            DateTime dt = new DateTime(2012, 10, 8);
            AddRate(dt, "EUR", 1.29m);
            AddRate(dt, "THB", 1 / 30.6m);
            AddRate(dt, "THY", 1 / 1.8m);
            AddRate(dt, "VND", 1 / 21000m);
            AddRate(dt, "ZZZ", 1); // Stock

            // Sort
            var keys = new List<string>(_dict.Keys);
            foreach (var key in keys)
            {
                _dict[key] = _dict[key].OrderBy(x => x.Date).ToList();
            }
        }

        public decimal ConvertToUsd(decimal amount, String currency, DateTime? date = null)
        {
            if (currency == "USD") { return amount; }

            if (date == null) { date = DateTime.Now.AddDays(1); }
            if (!_dict.ContainsKey(currency)) { throw new ArgumentException("No rate for currency: " + currency); }

            var rateList = GetRateList(currency);

            // Look backwards 
            var rate = rateList.LastOrDefault(x => x.Date <= date);
            if (rate == null)
            {
                // Look forward
                rate = rateList.FirstOrDefault(x => x.Date >= date);
            }

            return amount * rate.RateToUsd;
        }

        void AddRate(DateTime day, String currency, decimal rate)
        {
            var rateList = GetRateList(currency);
            var rateOnDay = new Rate() { Date = day, RateToUsd = rate };
            rateList.Add(rateOnDay);
        }

        List<Rate> GetRateList(String currency)
        {
            List<Rate> rateList;
            if (!_dict.TryGetValue(currency, out rateList))
            {
                rateList = new List<Rate>();
                _dict.Add(currency, rateList);
            }
            return rateList;
        }

        public class Rate
        {
            public DateTime Date;
            public decimal RateToUsd;
            public string Inverse { get { return String.Format("1/{0:0.00}", 1 / RateToUsd); } }
        }
    }
}
